#include "SequenceModel.h"
#include "modelViewRules.h"
#include "testableAssert.h"

SequenceModel::SequenceModel(QList<SequenceItem *> &eventList, QObject *parent) :
   QAbstractListModel(parent),
   m_eventList(eventList)
{
}

int SequenceModel::rowCount(const QModelIndex &) const
{
   return m_eventList.length();
}

Qt::ItemFlags SequenceModel::flags(const QModelIndex &) const
{
   return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
}

bool SequenceModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
   bool dataSet = false;

   if (role == Qt::EditRole)
   {
      T_ASSERT( index.row() >= 0);

      const SequenceItem * copyFrom = value.value<const SequenceItem *>();
      SequenceItem * item = m_eventList.at( index.row());

      item->setDelayMs( copyFrom->delayMs());
      item->setIndexOfNext( copyFrom->indexOfNext() );
      item->setLabel( copyFrom->label() );
      item->setType( copyFrom->type() );

      dataSet = true;
      emit layoutChanged();
   }

   return dataSet;
}

QVariant SequenceModel::data(const QModelIndex &index, int role) const
{
   QVariant value = QVariant();

   T_ASSERT (index.row() >= 0);

   const SequenceItem *item = m_eventList.at( index.row());
   T_ASSERT (item != NULL);

   switch (role)
   {
   case Qt::DisplayRole:
      value = QVariant(QString(item->label()));
      break;

   case modelViewRules::Binary:
   case Qt::EditRole:
      value = QVariant::fromValue<const SequenceItem *>(item);
      break;

   default:
      break;
   }


   return value;
}

/**
 * insert a new item at the end of the list
 */
void SequenceModel::createEmptyItem()
{
   /* there is no point in having a factory to produce
    * sequence item */
   SequenceItem * newItem = new SequenceItem();
   addSequenceItem( newItem);
}

void SequenceModel::addSequenceItem(SequenceItem *item)
{
   m_eventList << item;
   layoutChanged();
}

QVariant SequenceModel::headerData(int , Qt::Orientation , int ) const
{
   return QVariant();
}


bool SequenceModel::removeRows(int row, int count, const QModelIndex &)
{
   T_ASSERT( row >= 0);
   T_ASSERT( (row + count) <= rowCount(QModelIndex()) );

   if (count > 0)
   {
      beginRemoveRows(QModelIndex(), row, row + count - 1);

      for (int i = 0; i < count; ++i)
      {
         /* each 'remove' operation shitfs next element */
         m_eventList.removeAt( row );
      }

      endRemoveRows();
      emit layoutChanged();
   }

   return true;
}

/**
 * @brief base class reimplementation. Source and destination indexes are ignored.
 * @param sourceRow - first row to be moved
 * @param count - number of rows moved from \p sourceRow
 * @param destinationChild - final position of the first row moved
 *
 * @return true if succesfully moved; false otherwise
 */
bool SequenceModel::moveRows(const QModelIndex &/*sourceParent*/, int sourceRow, int count,
                             const QModelIndex &/*destinationParent*/, int destinationChild)
{
   bool moveDone = false;

   if ((sourceRow >= 0) && (sourceRow < rowCount()) &&
       (destinationChild >= 0) && (destinationChild < rowCount()) &&
       (count > 0) && (count <= rowCount())
      )
   {
      moveRows( sourceRow, count, destinationChild);
      moveDone = true;
   }

   return moveDone;
}

/**
 * @brief overload function that assumes that parameters are consistent
 */
void SequenceModel::moveRows(int sourceRow, int count, int destinationRow)
{
   for (int i=0; i < count; i++)
   {
      m_eventList.move( sourceRow + i, destinationRow + i );
   }

   /* this avoids need for BeginMoveRow and EndMoveRow */
   layoutChanged();
}

